package com.shj.em.config;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.shj.em.aa.entity.Resource;
import com.shj.em.aa.entity.Role;
import com.shj.em.aa.entity.User;
import com.shj.em.aa.service.ResourceService;
import com.shj.em.aa.service.RoleService;
import com.shj.em.aa.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;


/**
 * 在Shiro中，认证和授权最终是通过Realm来获取应用程序中的用户、角色及权限信息的。
 * 
 * @author huangjian
 *
 */
public class AuthRealm extends AuthorizingRealm{
	
	@Autowired
	private UserService userService;

	@Autowired
	private RoleService roleService;

	@Autowired
    private ResourceService resourceService;


	/**
	 * 认证过程会交由Realm中的doGetAuthenticationInfo(token)方法
	 * token -- 包含了页面传进来的用户名和密码信息
	 * 
	 * 此方法主要对用户进行验证，不通过则抛出AuthenticationException
	 */
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken up = (UsernamePasswordToken) token;
		String userId = up.getUsername();
		User user = userService.findByUserId(userId);
		
		if(user == null){
			throw new UnknownAccountException("账号或密码不正确");
		}

		if(user.getDelFlag() == 1){
			throw new LockedAccountException("账号已被锁定,请联系管理员");
		}

		String password = new String((char[]) token.getCredentials());
		// 密码错误
		if (!password.equals(user.getPassword())) {
			throw new IncorrectCredentialsException("账号或密码不正确");
		}
		
//		byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16));
//		return new SimpleAuthenticationInfo(user, user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
		return new SimpleAuthenticationInfo(user, password, getName());
//		return info;
	}
	
	/**
	 * 对用户进行授权的方法
	 * 在此方法中，需要把用户的角色，权限等信息查询出来，并放入返回的AuthorizationInfo中
	 */
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		User user = (User) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        // 根据用户名查询当前用户拥有的角色
        Set<Role> roles = roleService.findRolesByUserLoginId(user.getUserId());
        Set<String> roleNames = new HashSet<String>();
        for (Role role : roles) {
            roleNames.add(role.getRoleCode());
        }

        // 将角色名称提供给info
        authorizationInfo.setRoles(roleNames);

        // TODO 根据用户ID 查询当前用户权限
        List<Resource> resList = resourceService.findResByUserLoginId(user.getUserId());
        Set<String> permissionNames = new HashSet<>();
        for(Resource res : resList){
            permissionNames.add(res.getPerms());
        }
        // 将权限名称提供给info
        authorizationInfo.setStringPermissions(permissionNames);

        return authorizationInfo;
	}

}
